/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package store

// backend 初始化后端存储、mq
import (
	"fmt"
	"sync"

	"hundsun.com/hsl/hschain/common/config"
	"hundsun.com/hsl/hschain/store/db"
	"hundsun.com/hsl/hschain/store/mq"
	"hundsun.com/hsl/hschain/store/state"
)

var (
	// mq所加载插件类型
	mqName = "localmq"
	// db所加载插件类型
	defaultDBName = "leveldb"
	// statedb所加载插件类型
	stateName = "kvdb"
	// 存储账本数据句柄
	ledgerDBHandle db.Database
	// 存储状态数据DB句柄
	stateDBHandle db.Database
	// 存储p2p相关数据
	p2pDBHandle db.Database
	// 存储rpc相关数据
	rpcDBHandle db.Database
	// 后端部分配置
	mqConf    *config.PluginConfig
	stateConf *config.PluginConfig
	once      sync.Once
)

// 后端存储，yaml配置读取key
const (
	// ConfigKeyStoreLedgerdb ...
	ConfigKeyStoreLedgerdb = "store.ledgerdb"
	// ConfigKeyStoreLedgerdbName 账本数据库name
	ConfigKeyStoreLedgerdbName = "store.ledgerdb.name"
	// ConfigKeyStoreStatedb ...
	ConfigKeyStoreStatedb = "store.statedb"
	// ConfigKeyStoreStatedbName 状态数据库name
	ConfigKeyStoreStatedbName = "store.statedb.name"
	// ConfigKeyStoreP2pdb ...
	ConfigKeyStoreP2pdb = "store.p2pdb"
	// ConfigKeyStoreP2pdbName p2p数据库name
	ConfigKeyStoreP2pdbName = "store.p2pdb.name"
	// ConfigKeyStoreRpcdb ...
	ConfigKeyStoreRpcdb = "store.rpcdb"
	// ConfigKeyStoreRpcdbName rpc数据库名称
	ConfigKeyStoreRpcdbName = "store.rpcdb.name"
	// ConfigKeyStoreMq ...
	ConfigKeyStoreMq = "store.mq"
	// ConfigKeyStoreMqName mq名称
	ConfigKeyStoreMqName = "store.mq.name"
	// ConfigKeyStoreState ...
	ConfigKeyStoreState = "store.state"
	// ConfigKeyStoreStateName 状态数据结构名称
	ConfigKeyStoreStateName = "store.state.name"
)

// Initialize 初始化后端存储, 载入后端配置文件之后,再进行后端存储初始化
func Initialize() {
	once.Do(func() {
		var err error
		// load ledger db
		ldbConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreLedgerdb, nil)
		ldbName := config.GetStringConfigValue(ConfigKeyStoreLedgerdbName, defaultDBName)
		ldbConf := ldbConfs[ldbName]
		if ldbConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreLedgerdb))
		}
		ledgerDBHandle, err = db.NewDataBase(ldbConf)
		if err != nil {
			panic("InitBackend LedgerHandle " + ldbName + " fail" + err.Error())
		}
		// load state db
		sdbConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreStatedb, nil)
		sdbName := config.GetStringConfigValue(ConfigKeyStoreStatedbName, defaultDBName)
		sdbConf := sdbConfs[sdbName]
		if sdbConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreStatedb))
		}
		stateDBHandle, err = db.NewDataBase(sdbConf)
		if err != nil {
			panic("InitBackend stateDBHandle " + sdbName + " fail" + err.Error())
		}
		// load p2p db
		pdbConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreP2pdb, nil)
		pdbName := config.GetStringConfigValue(ConfigKeyStoreP2pdbName, defaultDBName)
		pdbConf := pdbConfs[pdbName]
		if pdbConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreP2pdb))
		}
		p2pDBHandle, err = db.NewDataBase(pdbConf)
		if err != nil {
			panic("InitBackend P2pDBHandle " + pdbName + " fail" + err.Error())
		}
		// load rpc db
		rdbConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreRpcdb, nil)
		rdbName := config.GetStringConfigValue(ConfigKeyStoreRpcdbName, defaultDBName)
		rdbConf := rdbConfs[rdbName]
		if rdbConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreRpcdb))
		}
		rpcDBHandle, err = db.NewDataBase(rdbConf)
		if err != nil {
			panic("InitBackend RpcDBHandle " + pdbName + " fail" + err.Error())
		}
		// mq config
		mqConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreMq, nil)
		mqName = config.GetStringConfigValue(ConfigKeyStoreMqName, mqName)
		mqConf = mqConfs[mqName]
		if mqConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreMq))
		}
		// state config
		stateConfs := config.GetPluginConfigsMapValue(ConfigKeyStoreState, nil)
		stateName = config.GetStringConfigValue(ConfigKeyStoreStateName, stateName)
		stateConf = stateConfs[stateName]
		if stateConf == nil {
			panic(fmt.Sprintf("config of plugin[%s] is nil", ConfigKeyStoreState))
		}
	})
}

// Close 后端存储关闭
func Close() {
	ldb := GetLedgerDB()
	if ldb != nil {
		ldb.Close()
	}
	sdb := GetStateDB()
	if sdb != nil {
		sdb.Close()
	}
	pdb := GetP2pDB()
	if pdb != nil {
		pdb.Close()
	}
	rdb := GetRPCDB()
	if rdb != nil {
		rdb.Close()
	}
}

// GetLedgerDB 获取账本数据库句柄
func GetLedgerDB() db.Database {
	return ledgerDBHandle
}

// GetStateDB 获取状态数据库句柄
func GetStateDB() db.Database {
	return stateDBHandle
}

// GetP2pDB 获取p2p数据库句柄
func GetP2pDB() db.Database {
	return p2pDBHandle
}

// GetRPCDB 获取rpc数据库句柄
func GetRPCDB() db.Database {
	return rpcDBHandle
}

// NewMqClient new mq client
func NewMqClient(mode string) (mq.Client, error) {
	return mq.NewMq(mqConf, mode)
}

// NewState new state
func NewState(dbm db.Database) (state.State, error) {
	return state.New(stateConf, dbm)
}
